grammar epigraph;

options {
  language = Java;
  output=AST;
  ASTLabelType=CommonTree; 
}


tokens{
}

@parser::header {
package epg;

import java.io.*;
import org.antlr.runtime.*;
}

@lexer::header
{
package epg;
}

// Define some methods and variables to use in the generated parser.

@members {
// main
/*
public static Gen code = null;
public static String module_name = new String();

public static void main(String[] args) {
	try {
		if (args.length == 1) {
			System.err.println("Parsing...");
			epigraphLexer lex = new epigraphLexer(new ANTLRFileStream(args[0]));
			code = new Gen(args[0]);
			CommonTokenStream tokens = new CommonTokenStream(lex);
			epigraphParser g = new epigraphParser(tokens);
			g.mainRule();
		} else
			System.err.println("Usage: java epigraphParser <file name>");

	} catch (Exception e) {
		System.err.println("exception: " + e);
		e.printStackTrace(System.err); // so we can get stack trace
	}
	code.close();
}
*/
}

prog:
    mainRule
;

mainRule: 
  module
  (declConst | declVar)*
  main_block
; 


main_block :
    block DOT!   
;

block:
    BEGIN^ (statement)* END //-> ^(BEGIN statement*) END
;

method:
  identifier^ LPAREN! (argument | identifier) (COMMA! (argument | identifier) )* RPAREN! SEMI!
;

argument:
  //expression
  value
;

//после правок править и noIfStatement
statement:
  simple_statement
  | ifStatement
  | declConst | declVar | method
;

simple_statement:
  assignmentStatement SEMI!
;

assignmentStatement:
  variable ASSIGN^ expression
;

variable:
  identifier
;

expression
    :
    simpleExpression
    ( (EQUAL! | NOT_EQUAL! | LT! | LE! | GE! | GT! ) simpleExpression )*
    ;
    
simpleExpression
    : term ( (PLUS! | MINUS! ) term )*
    ;

term
  : signedFactor ( (STAR! | SLASH! |  MOD! ) signedFactor )*
    ;

signedFactor
    : (PLUS!|MINUS!)? factor
    ;

factor
    : variable
    | LPAREN! expression RPAREN!
    | INT!
    ;
    
ifStatement:
//    IF^ expr
//    (statement)*
//    ENDIF! SEMI!
//    (
//      elseStatement
//    )?
     IF expr
    (statement)*
    END SEMI
    (
      elseStatement
    )?
    ->
    ^(IF expr ^(STATEMENT (statement)*) (elseStatement)? )
;

noIfStatement:
  simple_statement
  | declConst | declVar | method
;

elseStatement:
 // ELSE^ (statement)*  END! SEMI!
  ELSE^ (ifStatement | ( (noIfStatement)* END! SEMI! ) )
;

expr:
  LPAREN expression RPAREN
  ->
  ^(EXPRESSION expression)
;

module  :
  MODULE^ identifier SEMI! 
; 

string  : STRING;

declConst
  :
  CONST type_token COLON identifier ASSIGN value (COMMA identifier ASSIGN value )*  SEMI
  ->
  ^(CONST type_token ^( identifier value )* )
 
;


value: INT | CHAR | STRING | FLOAT;

declVar :
   type_token^ COLON! var (COMMA! var)* SEMI!
;

var:
  identifier^ (ASSIGN! value)?
;

type_token  :
  INTEGER_NAME
  | DOUBLE_NAME
  | FLOAT_NAME
  | BYTE_NAME
;

identifier : IDENTIFIER;
methodName : identifier;



//KEYWORDS
MODULE  : 'module'  ;
CONST   : 'const'   ;
INTEGER_NAME : 'int'     ;
DOUBLE_NAME  : 'double'  ;
FLOAT_NAME   : 'float'   ;
BYTE_NAME    : 'byte'   ;
BEGIN   : 'begin'   ;
END     : 'end'     ;
IF      : 'if'      ;
ELSE    : 'else'    ;


//OPERATORS
ASSIGN          : '='   ; 
COMMA           : ','   ;
SEMI            :  ';'  ;
COLON           : ':'   ;
DOT             : '.'   ;
EQUAL           : '=='  ;
NOT_EQUAL       : '!='  ;
LT              : '<'   ;
LE              : '<='  ;
GE              : '>='  ;
GT              : '>'   ;
LPAREN          : '('   ;
RPAREN          : ')'   ;
PLUS            : '+'   ;
MINUS           : '-'   ;
STAR            : '*'   ;
SLASH           : '/'   ;
MOD             : '%' ;


//other
EXPRESSION       : 'EXPRESSION' ;
STATEMENT        : 'STATEMENT' ;



IDENTIFIER  : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;
      
INT : DIGIT+
    ;
  

FLOAT
    :   ('0'..'9')+ '.' ('0'..'9')+ EXPONENT?
    //|   '.' ('0'..'9')+ EXPONENT?
    |   ('0'..'9')+ EXPONENT
    ;

COMMENT
    :   '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    |   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;

WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {$channel=HIDDEN;}
    ;

//STRING
//    :  '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
//    ;

STRING
    :  '"' ( ESC_SEQ | ~( '\\' |'"' | '\'') )+ '"'
    ;

CHAR:  '\'' ( ESC_SEQ | ~('\''|'\\') ) '\''
    ;

fragment
DIGIT: '0'..'9'
;

fragment
EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;

fragment
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;

fragment
ESC_SEQ
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UNICODE_ESC
    |   OCTAL_ESC
    ;

fragment
OCTAL_ESC
    :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7')
    ;

fragment
UNICODE_ESC
    :   '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
    ;